package lastfm
{
  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.HTTPStatusEvent;
  import flash.events.IEventDispatcher;
  import flash.events.IOErrorEvent;
  import flash.events.ProgressEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestMethod;
  import flash.net.URLVariables;
  import lastfm.events.RequestEvent;
  import PrivateVars.lastfm;
  import Tools.MD5;
  import Tools.UtilFunctions;

  /**
   * ...
   * @author Roman Marchenko
   */
  public class Request extends EventDispatcher
  {
    public static const API_URL:String = PrivateVars.lastfm.API_URL;
    public static const API_URL_POST:String = PrivateVars.lastfm.API_URL_POST;
    public static const API_KEY:String = PrivateVars.lastfm.API_KEY;

    private var savedParams:URLVariables;
    private var doSign:Boolean;
    private var isPost:Boolean;

    ///////////////////////////////////////////////////////////////////////////

    public function Request()
    {
    }

    public function send(params:URLVariables, sign:Boolean = false):void
    {
      savedParams = UtilFunctions.clone(params) as URLVariables;
      doSign = sign;
      isPost = false;

      params.api_key = API_KEY;
      if (doSign)
      {
        params.api_sig = signature(params);
      }

      var loader:URLLoader = new URLLoader;
      configureListeners(loader);

      trace("Request.send: " + API_URL + params.toString());
      var url:URLRequest = new URLRequest(API_URL + params.toString());

      try
      {
        loader.load(url);
      }
      catch (error:Error)
      {
        trace(error.name + ": " + error.message);
        var event:lastfm.events.RequestEvent = new RequestEvent(RequestEvent.ERROR);
        //                     "Error " + error.name + ": " + error.message);
        dispatchEvent(event);
      }
    }

    private function configureListeners(dispatcher:IEventDispatcher):void
    {
      dispatcher.addEventListener(Event.COMPLETE, completeHandler);
      dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
      //dispatcher.addEventListener(Event.OPEN, openHandler);
      //dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
      //dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
      //dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
    }

    ///////////////////////////////////////////////////////////////////////////

    private function ioErrorHandler(event:IOErrorEvent):void
    {
      trace("Request.ioErrorHandler: " + event);
      processServerResponse(RequestEvent.ERROR, event.target.data);
    }

    ///////////////////////////////////////////////////////////////////////////

    private function completeHandler(event:Event):void
    {
      trace("Request.completeHandler: " + event);
      processServerResponse(RequestEvent.OK, event.target.data);
    }

    ///////////////////////////////////////////////////////////////////////////

    private function processServerResponse(eventType:String, data:*):void
    {
      var newevent:RequestEvent = new RequestEvent(eventType);
      try
      {
        newevent.xml = new XML(data);
      }
      catch (error:Error)
      {
        // Do nothing, just suppress conversion errors.
        trace("Can't retrieve error description: " + error.message);
      }

      dispatchEvent(newevent);
    }

    private static function signature(params:Object):String
    {
      var arr:Array = new Array;
      for (var k:String in params)
      {
        arr.push(k);
      }

      arr = arr.sort();
      var sig:String = "";
      for (var i:int = 0; i < arr.length; ++i)
      {
        sig += arr[i] + params[arr[i]];
      }
      sig += PrivateVars.lastfm.SECRET;

      return MD5.hash(sig);
    }

    public function post(params:URLVariables):void
    {
      savedParams = UtilFunctions.clone(params) as URLVariables;
      isPost = true;

      params["api_key"] = API_KEY;
      params.api_sig = signature(params);

      var loader:URLLoader = new URLLoader;
      configureListeners(loader);

      trace("Request.post: " + API_URL_POST + ", " + params.toString());
      var url:URLRequest = new URLRequest(API_URL_POST);
      url.method = URLRequestMethod.POST;
      url.data = params;

      try
      {
        loader.load(url);
      }
      catch (error:Error)
      {
        trace(error.name + ": " + error.message);
        var event:lastfm.events.RequestEvent = new RequestEvent(RequestEvent.ERROR);
        //                     "Error " + error.name + ": " + error.message);
        dispatchEvent(event);
      }
    }

    public function redo():void
    {
      if (isPost)
      {
        post(savedParams);
      }
      else
      {
        send(savedParams, doSign);
      }
    }
  /*
     private function openHandler(event:Event):void {
     trace("openHandler: " + event);
     }

     private function progressHandler(event: ProgressEvent):void {
     trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
     }

     private function securityErrorHandler(event: SecurityErrorEvent):void {
     trace("securityErrorHandler: " + event);
     }

     private function httpStatusHandler(event: HTTPStatusEvent):void {
     trace("httpStatusHandler: " + event);
     }
   */
  }

}
